﻿using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using System.Windows.Ink;
using System.Windows.Media;
using ThePresenter.Windows.Ink;


namespace ThePresenter.Windows.Data
{
	[ValueConversion(typeof(StartupMode), typeof(bool?))]
	public class StartupModeToBooleanConverter : IValueConverter
	{
		#region IValueConverter Members
		/// <summary>
		/// Converts a value.
		/// </summary>
		/// <param name="value">The value produced by the binding source.</param>
		/// <param name="targetType">The type of the binding target property.</param>
		/// <param name="parameter">The converter parameter to use.</param>
		/// <param name="culture">The culture to use in the converter.</param>
		/// <returns>A converted value. If the method returns null, the valid null value is used.</returns>
		public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
		{
			if (value is StartupMode && parameter is string)
			{
				StartupMode param = (StartupMode)Enum.Parse(typeof(StartupMode), parameter.ToString());

				return new bool?((StartupMode)value == param);
			}
			else
			{
				return null;
			}
		}

		/// <summary>
		/// Converts a value.
		/// </summary>
		/// <param name="value">The value that is produced by the binding target.</param>
		/// <param name="targetType">The type to convert to.</param>
		/// <param name="parameter">The converter parameter to use.</param>
		/// <param name="culture">The culture to use in the converter.</param>
		/// <returns>A converted value. If the method returns null, the valid null value is used.</returns>
		public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
		{
			if ((value is bool || value is bool?) && parameter is string)
			{
				StartupMode param = (StartupMode)Enum.Parse(typeof(StartupMode), parameter.ToString());

				if (object.Equals(value, true))
					return param;
				else
					return null;
			}
			else
			{
				return DependencyProperty.UnsetValue;
			}
		}
		#endregion
	}


	[ValueConversion(typeof(Shape), typeof(ImageSource))]
	public class ShapeToImageSourceValueConverter : IMultiValueConverter, IValueConverter
	{
		#region IValueConverter Members
		/// <summary>
		/// Converts a value.
		/// </summary>
		/// <param name="value">The value produced by the binding source.</param>
		/// <param name="targetType">The type of the binding target property.</param>
		/// <param name="parameter">The converter parameter to use.</param>
		/// <param name="culture">The culture to use in the converter.</param>
		/// <returns>
		/// A converted value. If the method returns null, the valid null value is used.
		/// </returns>
		public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
		{
			if ( !(value is Shape))
				//throw new ArgumentException("Value must be of type Shape.", "parameter");
				return DependencyProperty.UnsetValue;

			if ( !(parameter is Size))
				//throw new ArgumentException("Parameter must be of type Size.", "parameter");
				return DependencyProperty.UnsetValue;

			var size = (Size)parameter;
			var shape = (Shape)value;

			return Shape.GetThumbnail(shape, size);
		}

		/// <summary>
		/// Converts a value.
		/// </summary>
		/// <param name="value">The value that is produced by the binding target.</param>
		/// <param name="targetType">The type to convert to.</param>
		/// <param name="parameter">The converter parameter to use.</param>
		/// <param name="culture">The culture to use in the converter.</param>
		/// <returns>
		/// A converted value. If the method returns null, the valid null value is used.
		/// </returns>
		public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
		{
			throw new NotImplementedException();
		}
		#endregion


		#region IMultiValueConverter Members
		/// <summary>
		/// Converts source values to a value for the binding target. The data binding engine calls this method when it propagates the values from source bindings to the binding target.
		/// </summary>
		/// <param name="values">The array of values that the source bindings in the <see cref="T:System.Windows.Data.MultiBinding"/> produces. The value <see cref="F:System.Windows.DependencyProperty.UnsetValue"/> indicates that the source binding has no value to provide for conversion.</param>
		/// <param name="targetType">The type of the binding target property.</param>
		/// <param name="parameter">The converter parameter to use.</param>
		/// <param name="culture">The culture to use in the converter.</param>
		/// <returns>
		/// A converted value.
		/// If the method returns null, the valid null value is used.
		/// A return value of <see cref="T:System.Windows.DependencyProperty"/>.<see cref="F:System.Windows.DependencyProperty.UnsetValue"/> indicates that the converter did not produce a value, and that the binding will use the <see cref="P:System.Windows.Data.BindingBase.FallbackValue"/> if it is available, or else will use the default value.
		/// A return value of <see cref="T:System.Windows.Data.Binding"/>.<see cref="F:System.Windows.Data.Binding.DoNothing"/> indicates that the binding does not transfer the value or use the <see cref="P:System.Windows.Data.BindingBase.FallbackValue"/> or the default value.
		/// </returns>
		public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
		{
			try
			{
				var strokes = values[0] as StrokeCollection;
				var size = new Size((double)values[1], (double)values[2]);

				return Shape.GetThumbnail(strokes, size);
			}
			catch (InvalidCastException)
			{
				return DependencyProperty.UnsetValue;
			}
		}

		/// <summary>
		/// Converts a binding target value to the source binding values.
		/// </summary>
		/// <param name="value">The value that the binding target produces.</param>
		/// <param name="targetTypes">The array of types to convert to. The array length indicates the number and types of values that are suggested for the method to return.</param>
		/// <param name="parameter">The converter parameter to use.</param>
		/// <param name="culture">The culture to use in the converter.</param>
		/// <returns>
		/// An array of values that have been converted from the target value back to the source values.
		/// </returns>
		public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
		{
			throw new NotImplementedException();
		}
		#endregion
	}


	[ValueConversion(typeof(InkCanvasTool), typeof(bool?))]
	public class InkCanvasToolToBooleanValueConverter : IValueConverter
	{
		#region IValueConverter Members
		/// <summary>
		/// Converts a value.
		/// </summary>
		/// <param name="value">The value produced by the binding source.</param>
		/// <param name="targetType">The type of the binding target property.</param>
		/// <param name="parameter">The converter parameter to use.</param>
		/// <param name="culture">The culture to use in the converter.</param>
		/// <returns>A converted value. If the method returns null, the valid null value is used.</returns>
		public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
		{
			if (value is InkCanvasTool)
			{
				if (parameter is string || parameter is InkCanvasTool)
				{
					return new bool?(value.ToString().Equals(parameter.ToString()));
				}
			}

			return null;
		}

		/// <summary>
		/// Converts a value.
		/// </summary>
		/// <param name="value">The value that is produced by the binding target.</param>
		/// <param name="targetType">The type to convert to.</param>
		/// <param name="parameter">The converter parameter to use.</param>
		/// <param name="culture">The culture to use in the converter.</param>
		/// <returns>A converted value. If the method returns null, the valid null value is used.</returns>
		public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
		{
			if (value is bool || value is bool?)
			{
				if (parameter is string || parameter is InkCanvasTool)
				{
					if (true.Equals(value))
						return (InkCanvasTool)Enum.Parse(typeof(InkCanvasTool), parameter.ToString());
					else
						return null;
				}
			}

			return DependencyProperty.UnsetValue;
		}
		#endregion
	}


	[ValueConversion(typeof(FrameworkElement), typeof(ImageSource))]
	public class FrameworkElementToImageSourceValueConverter : IMultiValueConverter
	{
		#region IMultiValueConverter Members
		/// <summary>
		/// Converts source values to a value for the binding target. The data binding engine calls this method when it propagates the values from source bindings to the binding target.
		/// </summary>
		/// <param name="values">The array of values that the source bindings in the <see cref="T:System.Windows.Data.MultiBinding"/> produces. The value <see cref="F:System.Windows.DependencyProperty.UnsetValue"/> indicates that the source binding has no value to provide for conversion.</param>
		/// <param name="targetType">The type of the binding target property.</param>
		/// <param name="parameter">The converter parameter to use.</param>
		/// <param name="culture">The culture to use in the converter.</param>
		/// <returns>
		/// A converted value.
		/// If the method returns null, the valid null value is used.
		/// A return value of <see cref="T:System.Windows.DependencyProperty"/>.<see cref="F:System.Windows.DependencyProperty.UnsetValue"/> indicates that the converter did not produce a value, and that the binding will use the <see cref="P:System.Windows.Data.BindingBase.FallbackValue"/> if it is available, or else will use the default value.
		/// A return value of <see cref="T:System.Windows.Data.Binding"/>.<see cref="F:System.Windows.Data.Binding.DoNothing"/> indicates that the binding does not transfer the value or use the <see cref="P:System.Windows.Data.BindingBase.FallbackValue"/> or the default value.
		/// </returns>
		public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
		{
			if (values != null)
			{
				if (values[0] is FrameworkElement && values[1] is double && values[2] is double)
				{
					return (values[0] as FrameworkElement).GetThumbnail(new Size((double)values[1], (double)values[2]));
				}
			}

			return null;
		}

		/// <summary>
		/// Converts a binding target value to the source binding values.
		/// </summary>
		/// <param name="value">The value that the binding target produces.</param>
		/// <param name="targetTypes">The array of types to convert to. The array length indicates the number and types of values that are suggested for the method to return.</param>
		/// <param name="parameter">The converter parameter to use.</param>
		/// <param name="culture">The culture to use in the converter.</param>
		/// <returns>
		/// An array of values that have been converted from the target value back to the source values.
		/// </returns>
		public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
		{
			throw new NotImplementedException();
		}
		#endregion
	}


	[ValueConversion(typeof(PresentationBindingMode), typeof(bool))]
	public class BindingModeToBooleanConverter : IValueConverter
	{
		#region IValueConverter Members
		/// <summary>
		/// Converts a value.
		/// </summary>
		/// <param name="value">The value produced by the binding source.</param>
		/// <param name="targetType">The type of the binding target property.</param>
		/// <param name="parameter">The converter parameter to use.</param>
		/// <param name="culture">The culture to use in the converter.</param>
		/// <returns>
		/// A converted value. If the method returns null, the valid null value is used.
		/// </returns>
		public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
		{
			if ((value is PresentationBindingMode) == false)
				throw new ArgumentException("Must be of type ThePresenter.PresentationBindingMode.", "value");

			if ((parameter is string) == false)
				throw new ArgumentException("Must be of type System.String.", "parameter");

			var mode = (PresentationBindingMode)value;
			var elem = parameter.ToString();

			switch (elem)
			{
				// TODO Add other panels into value converter.

				// Always enabled panels
				case "DrawingProperties":
					return true;

				// Client enabled panels
				case "PollsList_Client":
					return mode == PresentationBindingMode.PresentationViewer;

				// Server enabled panels
				case "Polls":
				case "Clients":
				case "PollsList_Server":
					return mode == PresentationBindingMode.PresentationHost;

				default:
					return null;
			}
		}

		/// <summary>
		/// Converts a value.
		/// </summary>
		/// <param name="value">The value that is produced by the binding target.</param>
		/// <param name="targetType">The type to convert to.</param>
		/// <param name="parameter">The converter parameter to use.</param>
		/// <param name="culture">The culture to use in the converter.</param>
		/// <returns>
		/// A converted value. If the method returns null, the valid null value is used.
		/// </returns>
		public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
		{
			throw new NotImplementedException();
		}
		#endregion
	}


	[ValueConversion(typeof(object), typeof(bool))]
	public class AreEqualsValueConverter : IValueConverter
	{
		#region IValueConverter Members
		/// <summary>
		/// Converts a value.
		/// </summary>
		/// <param name="value">The value produced by the binding source.</param>
		/// <param name="targetType">The type of the binding target property.</param>
		/// <param name="parameter">The converter parameter to use.</param>
		/// <param name="culture">The culture to use in the converter.</param>
		/// <returns>
		/// A converted value. If the method returns null, the valid null value is used.
		/// </returns>
		public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
		{
			if (object.Equals(value, parameter))
			{
				return true;
			}
			else if (value != null && parameter != null)
			{
				if (value.GetType().Name == "SolidColorBrush")
				{
					Color wpf_color;

					if (parameter.ToString().StartsWith("#"))
					{
						wpf_color = Helpers.GetColorFromHexString(parameter.ToString());
					}
					else // named color
					{
						var gdi_color = System.Drawing.Color.FromName(parameter.ToString());
						wpf_color = Color.FromArgb(gdi_color.A, gdi_color.R, gdi_color.G, gdi_color.B);
					}

					return ((SolidColorBrush)value).Color.Equals(wpf_color);
				}
				else
				{
					return object.Equals(value.ToString(), parameter.ToString());
				}
			}
			else
			{
				return null;
			}
		}

		/// <summary>
		/// Converts a value.
		/// </summary>
		/// <param name="value">The value that is produced by the binding target.</param>
		/// <param name="targetType">The type to convert to.</param>
		/// <param name="parameter">The converter parameter to use.</param>
		/// <param name="culture">The culture to use in the converter.</param>
		/// <returns>
		/// A converted value. If the method returns null, the valid null value is used.
		/// </returns>
		public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
		{
			if (value is bool && (bool)value)
				return parameter;
			else
				//return DependencyProperty.UnsetValue;
				return null;
		}
		#endregion
	}
}
